package com.rules.admin.parser;

import com.alibaba.fastjson.JSONObject;
import com.rules.admin.expression.*;
import com.rules.admin.expression.operators.Parenthesis;
import com.rules.admin.expression.operators.arithmetic.*;
import com.rules.admin.expression.operators.conditional.AndExpression;
import com.rules.admin.expression.operators.conditional.OrExpression;
import com.rules.admin.expression.operators.relational.*;
import com.rules.admin.expression.value.*;
import com.rules.admin.utils.Templet;
import com.rules.admin.utils.TempletRegister;
import com.google.common.collect.Lists;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Pattern;

public class ParserUtils {
   private static final Logger LOGGER = LoggerFactory.getLogger(ParserUtils.class);

   protected static Expression parseCondition(Map<String, Object> condition) {
      if (condition.containsKey("oper")) {
         SetValue setValue = null;
         String oper = MapUtils.getString(condition, "oper");
         BinaryExpression binaryExpression = null;
         if (StringUtils.equals("+", oper)) {
            Addition addition = new Addition();
         } else if (StringUtils.equals("/", oper)) {
            Division division = new Division();
         } else if (StringUtils.equals("%", oper)) {
            Modulo modulo = new Modulo();
         } else if (StringUtils.equals("*", oper)) {
            Multiplication multiplication = new Multiplication();
         } else if (StringUtils.equals("-", oper)) {
            Subtraction subtraction = new Subtraction();
         } else if (StringUtils.equals("&&", oper) || StringUtils.equals("unit&&", oper)) {
            AndExpression andExpression = new AndExpression();
         } else if (StringUtils.equals("||", oper) || StringUtils.equals("unit||", oper)) {
            OrExpression orExpression = new OrExpression();
         } else if (StringUtils.equals("contains", oper)) {
            Contains contains = new Contains();
         } else if (StringUtils.equals("==", oper)) {
            Equals equals = new Equals();
         } else if (StringUtils.equals("!=", oper)) {
            NotEquals notEquals = new NotEquals();
         } else if (StringUtils.equals("exist", oper)) {
            Exist exist = new Exist();
         } else if (StringUtils.equals(">=", oper)) {
            GreaterEqualsThan greaterEqualsThan = new GreaterEqualsThan();
         } else if (StringUtils.equals(">", oper)) {
            GreaterThan greaterThan = new GreaterThan();
         } else if (StringUtils.equals("isNull", oper)) {
            IsNull isNull = new IsNull();
         } else if (StringUtils.equals("memberOf", oper)) {
            MemberOf memberOf = new MemberOf();
         } else if (StringUtils.equals("<=", oper)) {
            MinorEqualsThan minorEqualsThan = new MinorEqualsThan();
         } else if (StringUtils.equals("<", oper)) {
            MinorThan minorThan = new MinorThan();
         } else if (StringUtils.equals("notContain", oper)) {
            NotContains notContains = new NotContains();
         } else if (StringUtils.equals("regexMatch", oper)) {
            RegexMatch regexMatch = new RegexMatch();
         } else if (StringUtils.equals("setValue", oper)) {
            setValue = new SetValue();
         }
         if (setValue != null) {
            Object left = MapUtils.getObject(condition, "left");
            setValue.setLeftExpression(parseCondition(left));
         }
         if (setValue != null) {
            Object right = MapUtils.getObject(condition, "right");
            setValue.setRightExpression(parseCondition(right));
         }
         return (Expression)setValue;
      }
      if (condition.containsKey("type")) {
         String type = MapUtils.getString(condition, "type");
         if (StringUtils.equals(type, "const")) {
            Object value = MapUtils.getObject(condition, "value");
            Object valueType = MapUtils.getObject(condition, "valueType");
            Pattern pattern = Pattern.compile("^(\\-|\\+)?\\d+(\\.\\d+)?$");
            if (valueType == null) {
               if (!"".equals(value.toString()) && value.toString().matches("[0-9]*") && value.toString().length() < 10 && !value.toString().startsWith("0"))
                  return parseCondition(Integer.valueOf(value.toString()));
               if (!"".equals(value.toString()) && value.toString().matches("[0-9]*") && value.toString().length() >= 10 && !value.toString().startsWith("0"))
                  return parseCondition(Long.valueOf(value.toString()));
               if (pattern.matcher(value.toString()).matches() && !"".equals(value.toString()) && value.toString().indexOf(".") > 0)
                  return parseCondition(Double.valueOf(value.toString()));
               if ("null".equals(value)) {
                  value = null;
               } else if ("''".equals(value)) {
                  value = "";
               }
               return parseCondition(value);
            }
            if ("String".equals(valueType)) {
               if ("null".equals(value)) {
                  value = null;
               } else if ("''".equals(value)) {
                  value = "";
               }
               return parseCondition(value);
            }
            if ("Number".equals(valueType)) {
               if (!"".equals(value.toString()) && (value.toString().matches("[0-9]*") || value.toString().matches("-[0-9]*")) && value.toString().length() < 10)
                  return parseCondition(Integer.valueOf(value.toString()));
               if (!"".equals(value.toString()) && value.toString().matches("[0-9]*") && value.toString().length() >= 10)
                  return parseCondition(Long.valueOf(value.toString()));
               if (pattern.matcher(value.toString()).matches() && !"".equals(value.toString()) && value.toString().indexOf(".") > 0)
                  return parseCondition(Double.valueOf(value.toString()));
            }
         } else {
            if (StringUtils.equals(type, "dict")) {
               String value = MapUtils.getString(condition, "value");
               return parseCondition(value);
            }
            if (StringUtils.equals(type, "breakPackage"))
               return (Expression)new BreakPackage();
            if (StringUtils.equals(type, "breakAssembly"))
               return (Expression)new BreakAssembly();
            if (StringUtils.equals(type, "model")) {
               String value = MapUtils.getString(condition, "value");
               return (Expression)new Property("$model.attr(\"" + value + "\")");
            }
            if (StringUtils.equals(type, "setModel")) {
               Object modelId = MapUtils.getObject(condition, "modelId");
               Object modelValue = MapUtils.getObject(condition, "modelValue");
               return (Expression)new SetModel(parseCondition(modelId), parseCondition(modelValue));
            }
            if (StringUtils.equals(type, "listValue")) {
               String source = MapUtils.getString(condition, "source");
               return (Expression)new GetListValue(source);
            }
            if (StringUtils.equals(type, "listObj")) {
               String source = MapUtils.getString(condition, "source");
               return (Expression)new GetListObj(source);
            }
            if (StringUtils.equals("setRtnValue", type)) {
               Object obj = condition.get("value");
               ExecuteExpression executeExpression = new ExecuteExpression("$context", "setRtnValue");
               if (obj instanceof String)
                  executeExpression.addParam((Expression)new StringValue((String)obj));
               if (obj instanceof Number || obj instanceof Boolean)
                  executeExpression.addParam((Expression)new StringValue("'" + obj + "'"));
               if (obj instanceof Map) {
                  Expression exepression = parseCondition((Map<String, Object>)obj);
                  executeExpression.addParam((Expression)new StringValue(exepression.toString().replaceAll("\\\"", "\\\\\"")));
               }
               if (obj instanceof List) {
                  String exepression = generatorMVELExpression((List<Object>)obj);
                  executeExpression.addParam((Expression)new StringValue(exepression.replaceAll("\\\"", "\\\\\"")));
               }
               return (Expression)executeExpression;
            }
            if (StringUtils.equals("parenthesis", type)) {
               Object expression = MapUtils.getObject(condition, "expression");
               return (Expression)new Parenthesis(parseCondition(expression));
            }
            if (StringUtils.equals("compareHour", type)) {
               Object sourceConfig = MapUtils.getObject(condition, "source");
               Expression sourceExpression = parseCondition(sourceConfig);
               Object hoursConfig = MapUtils.getObject(condition, "hours");
               Expression hoursExpression = parseCondition(hoursConfig);
               return (Expression)new ExecuteExpression("RuleDateUtils", "compareHour", new Expression[] { sourceExpression, hoursExpression });
            }
            if (StringUtils.equals("replaceDate", type)) {
               Object sourceConfig = MapUtils.getObject(condition, "source");
               Expression sourceExpression = parseCondition(sourceConfig);
               Object hoursConfig = MapUtils.getObject(condition, "hours");
               Expression hoursExpression = parseCondition(hoursConfig);
               return (Expression)new ExecuteExpression("RuleDateUtils", "replaceDate", new Expression[] { sourceExpression, hoursExpression });
            }
            if (StringUtils.equals("addHours", type) || StringUtils.equals("countHours", type)) {
               Object sourceConfig = MapUtils.getObject(condition, "source");
               Expression sourceExpression = parseCondition(sourceConfig);
               Object hoursConfig = MapUtils.getObject(condition, "hours");
               Expression hoursExpression = parseCondition(hoursConfig);
               return (Expression)new ExecuteExpression("RuleDateUtils", type, new Expression[] { sourceExpression, hoursExpression });
            }
            if (StringUtils.equals("startWith", type)) {
               Object sourceConfig = MapUtils.getObject(condition, "source");
               Expression sourceExpression = parseCondition(sourceConfig);
               Object hoursConfig = MapUtils.getObject(condition, "str");
               Expression hoursExpression = parseCondition(hoursConfig);
               return (Expression)new ExecuteExpression("Tools", "startWith", new Expression[] { sourceExpression, hoursExpression });
            }
            if (StringUtils.equals("endsWith", type)) {
               Object sourceConfig = MapUtils.getObject(condition, "source");
               Expression sourceExpression = parseCondition(sourceConfig);
               Object hoursConfig = MapUtils.getObject(condition, "str");
               Expression hoursExpression = parseCondition(hoursConfig);
               return (Expression)new ExecuteExpression("Tools", "endsWith", new Expression[] { sourceExpression, hoursExpression });
            }
            if (StringUtils.equals("matchWith", type)) {
               Object sourceConfig = MapUtils.getObject(condition, "source");
               Expression sourceExpression = parseCondition(sourceConfig);
               Object hoursConfig = MapUtils.getObject(condition, "str");
               Expression hoursExpression = parseCondition(hoursConfig);
               return (Expression)new ExecuteExpression("Tools", "matchWith", new Expression[] { sourceExpression, hoursExpression });
            }
            if (StringUtils.equals("lastDateTime", type)) {
               Object sourceConfig = MapUtils.getObject(condition, "source");
               Expression sourceExpression = parseCondition(sourceConfig);
               return (Expression)new ExecuteExpression("RuleDateUtils", "lastDayTime", new Expression[] { sourceExpression });
            }
            if (StringUtils.equals("nowDate", type))
               return (Expression)new ExecuteExpression("RuleDateUtils", "nowDate");
            if (StringUtils.equals(type, "matcher")) {
               Object valueConfig = MapUtils.getObject(condition, "source");
               Expression valueExpression = parseCondition(valueConfig);
               Object expressionConfig = MapUtils.getObject(condition, "str");
               Expression expressionExpression = parseCondition(expressionConfig);
               return (Expression)new ExecuteExpression("Tools", "matcher", new Expression[] { valueExpression, expressionExpression });
            }
            if (StringUtils.equals("remoteService", type)) {
               Object codeConfig = MapUtils.getObject(condition, "serviceCode");
               Expression codeExpression = parseCondition(codeConfig);
               List list = (List)MapUtils.getObject(condition, "params");
               List expressionList = Lists.newArrayList();
               expressionList.add("$context");
               expressionList.add(codeExpression);
               for (Object obj : list)
                  expressionList.add(parseCondition(obj));
               return (Expression)new ExecuteExpression("Tools", "executeEsb", expressionList);
            }
            if (StringUtils.equals("JDBCService", type)) {
               Object codeConfig = MapUtils.getObject(condition, "sqlName");
               Expression codeExpression = parseCondition(codeConfig);
               Object columnConfig = MapUtils.getObject(condition, "sqlColumn");
               Expression columnExpression = parseCondition(columnConfig);
               List list = (List)MapUtils.getObject(condition, "params");
               List expressionList = Lists.newArrayList();
               expressionList.add("$context");
               expressionList.add(codeExpression);
               expressionList.add(columnExpression);
               for (Object obj : list)
                  expressionList.add(parseCondition(obj));
               return (Expression)new ExecuteExpression("Tools", "executeJDBC", expressionList);
            }
            if (StringUtils.equals("Dubbo", type)) {
               Object nameConfig = MapUtils.getObject(condition, "dubboName");
               Expression codeExpression = parseCondition(nameConfig);
               List list = (List)MapUtils.getObject(condition, "params");
               List expressionList = Lists.newArrayList();
               expressionList.add("$context");
               expressionList.add(codeExpression);
               for (Object obj : list)
                  expressionList.add(parseCondition(obj));
               return (Expression)new ExecuteExpression("Tools", "executeDubbo", expressionList);
            }
            if (StringUtils.equals("springCloudService", type)) {
               Object nameConfig = MapUtils.getObject(condition, "requestMapping");
               Expression codeExpression = parseCondition(nameConfig);
               List list = (List)MapUtils.getObject(condition, "params");
               List expressionList = Lists.newArrayList();
               expressionList.add("$context");
               expressionList.add(codeExpression);
               for (Object obj : list)
                  expressionList.add(parseCondition(obj));
               return (Expression)new ExecuteExpression("Tools", "executeSpringCloud", expressionList);
            }
            if (StringUtils.equals("groovyShellService", type)) {
               Object nameConfig = MapUtils.getObject(condition, "shellName");
               Expression codeExpression = parseCondition(nameConfig);
               List list = (List)MapUtils.getObject(condition, "params");
               List expressionList = Lists.newArrayList();
               expressionList.add("$context");
               expressionList.add(codeExpression);
               for (Object obj : list)
                  expressionList.add(parseCondition(obj));
               return (Expression)new ExecuteExpression("Tools", "executeGroovyShell", expressionList);
            }
            if (StringUtils.equals("validator", type)) {
               Object nameConfig = MapUtils.getObject(condition, "validatorName");
               Expression codeExpression = parseCondition(nameConfig);
               List list = (List)MapUtils.getObject(condition, "params");
               List  expressionList = Lists.newArrayList();
               expressionList.add("$context");
               expressionList.add(codeExpression);
               for (Object obj : list)
                  expressionList.add(parseCondition(obj));
               return (Expression)new ExecuteExpression("Tools", "validatorData", expressionList);
            }
            if (StringUtils.equals("dateFormat", type)) {
               List list = (List)MapUtils.getObject(condition, "params");
               List<Expression> expressionList = Lists.newArrayList();
               for (Object obj : list)
                  expressionList.add(parseCondition(obj));
               return (Expression)new ExecuteExpression("RuleDateUtils", "dateFormat", expressionList);
            }
            if (StringUtils.equals("dateToString", type)) {
               List list = (List)MapUtils.getObject(condition, "params");
               List<Expression> expressionList = Lists.newArrayList();
               for (Object obj : list)
                  expressionList.add(parseCondition(obj));
               return (Expression)new ExecuteExpression("RuleDateUtils", "dateToString", expressionList);
            }
            if (StringUtils.equals("dateToWeekDay", type)) {
               List list = (List)MapUtils.getObject(condition, "params");
               List<Expression> expressionList = Lists.newArrayList();
               for (Object obj : list)
                  expressionList.add(parseCondition(obj));
               return (Expression)new ExecuteExpression("RuleDateUtils", "dateToWeekDay", expressionList);
            }
            if (StringUtils.equals("listSize", type)) {
               List list = (List)MapUtils.getObject(condition, "params");
               List<Expression> expressionList = Lists.newArrayList();
               for (Object obj : list)
                  expressionList.add(parseCondition(obj));
               return (Expression)new ExecuteExpression("Tools", "getListSize", expressionList);
            }
            if (StringUtils.equals("isHolidays", type)) {
               List list = (List)MapUtils.getObject(condition, "params");
               List<Expression> expressionList = Lists.newArrayList();
               for (Object obj : list)
                  expressionList.add(parseCondition(obj));
               return (Expression)new ExecuteExpression("Tools", "isHolidays", expressionList);
            }
            if (StringUtils.equals("middleDate", type)) {
               List list = (List)MapUtils.getObject(condition, "params");
               List<Expression> expressionList = Lists.newArrayList();
               for (Object obj : list)
                  expressionList.add(parseCondition(obj));
               return (Expression)new ExecuteExpression("RuleDateUtils", "middleDate", expressionList);
            }
            if (StringUtils.equals("monthDays", type)) {
               List list = (List)MapUtils.getObject(condition, "params");
               List<Expression> expressionList = Lists.newArrayList();
               for (Object obj : list)
                  expressionList.add(parseCondition(obj));
               return (Expression)new ExecuteExpression("RuleDateUtils", "monthDays", expressionList);
            }
            if (StringUtils.equals("lastDayOfMonth", type)) {
               List list = (List)MapUtils.getObject(condition, "params");
               List<Expression> expressionList = Lists.newArrayList();
               for (Object obj : list)
                  expressionList.add(parseCondition(obj));
               return (Expression)new ExecuteExpression("RuleDateUtils", "lastDayOfMonth", expressionList);
            }
            if (StringUtils.equals("getMonth", type)) {
               List list = (List)MapUtils.getObject(condition, "params");
               List<Expression> expressionList = Lists.newArrayList();
               for (Object obj : list)
                  expressionList.add(parseCondition(obj));
               return (Expression)new ExecuteExpression("RuleDateUtils", "getMonth", expressionList);
            }
            if (StringUtils.equals("Rate", type)) {
               Object rateValue = MapUtils.getObject(condition, "RateValue");
               Expression rateValueExpression = parseCondition(rateValue);
               Object rate = MapUtils.getObject(condition, "Rate");
               Expression rateExpression = parseCondition(rate);
               Object countValue = MapUtils.getObject(condition, "countValue");
               Expression countExpression = parseCondition(countValue);
               List<Expression> expressionList = Lists.newArrayList();
               if (countExpression instanceof NullValue) {
                  expressionList.add(rateValueExpression);
                  expressionList.add(rateExpression);
                  return (Expression)new ExecuteExpression("Tools", "rate", expressionList);
               }
               expressionList.add(rateValueExpression);
               expressionList.add(rateExpression);
               expressionList.add(countExpression);
               return (Expression)new ExecuteExpression("Tools", "rate", expressionList);
            }
            if (StringUtils.equals("MAX", type)) {
               List list = (List)MapUtils.getObject(condition, "params");
               List<Expression> expressionList = Lists.newArrayList();
               for (Object obj : list)
                  expressionList.add(parseCondition(obj));
               return (Expression)new ExecuteExpression("Tools", "max", expressionList);
            }
            if (StringUtils.equals("MIN", type)) {
               List list = (List)MapUtils.getObject(condition, "params");
               List<Expression> expressionList = Lists.newArrayList();
               for (Object obj : list)
                  expressionList.add(parseCondition(obj));
               return (Expression)new ExecuteExpression("Tools", "min", expressionList);
            }
            if (StringUtils.equals("AVG", type)) {
               List list = (List)MapUtils.getObject(condition, "params");
               List<Expression> expressionList = Lists.newArrayList();
               for (Object obj : list)
                  expressionList.add(parseCondition(obj));
               return (Expression)new ExecuteExpression("Tools", "avg", expressionList);
            }
            if (StringUtils.equals("SUM", type)) {
               List list = (List)MapUtils.getObject(condition, "params");
               List<Expression> expressionList = Lists.newArrayList();
               for (Object obj : list)
                  expressionList.add(parseCondition(obj));
               return (Expression)new ExecuteExpression("Tools", "sum", expressionList);
            }
            if (StringUtils.equals("rounding", type)) {
               List list = (List)MapUtils.getObject(condition, "params");
               List<Expression> expressionList = Lists.newArrayList();
               for (Object obj : list)
                  expressionList.add(parseCondition(obj));
               return (Expression)new ExecuteExpression("Tools", "rounding", expressionList);
            }
            if (StringUtils.equals("Exception", type)) {
               List list = (List)MapUtils.getObject(condition, "params");
               List expressionList = Lists.newArrayList();
               expressionList.add("$context");
               for (Object obj : list)
                  expressionList.add(parseCondition(obj));
               return (Expression)new ExecuteExpression("Tools", "exception", expressionList);
            }
            if (StringUtils.equals("throw", type)) {
               Object message = MapUtils.getObject(condition, "message");
               Expression mesExpression = parseCondition(message);
               return (Expression)new ExecuteExpression("Tools", "throwException", new Expression[] { mesExpression });
            }
            if (StringUtils.equals("execute", type)) {
               String code = MapUtils.getString(condition, "code");
               Object source = MapUtils.getObject(condition, "source");
               Expression sourceExpression = parseCondition(source);
               Object varValue = MapUtils.getObject(condition, "value");
               Expression valueExpression = parseCondition(varValue);
               return (Expression)new SpecialExpression(type, code, sourceExpression.toString(), valueExpression.toString());
            }
            if (StringUtils.equals("strLength", type)) {
               List list = (List)MapUtils.getObject(condition, "params");
               List<Expression> expressionList = Lists.newArrayList();
               for (Object obj : list)
                  expressionList.add(parseCondition(obj));
               return (Expression)new ExecuteExpression("Tools", "StringLength", expressionList);
            }
            if (StringUtils.equals("MapPut", type)) {
               Object key = MapUtils.getObject(condition, "key");
               Expression keyExpression = parseCondition(key);
               Object map = MapUtils.getObject(condition, "map");
               Expression mapExpression = parseCondition(map);
               Object value = MapUtils.getObject(condition, "value");
               Expression valueExpression = parseCondition(value);
               List<Expression> expressionList = Lists.newArrayList();
               expressionList.add(mapExpression);
               expressionList.add(keyExpression);
               expressionList.add(valueExpression);
               return (Expression)new ExecuteExpression("Tools", "putMap", expressionList);
            }
            if (StringUtils.equals("MapGet", type)) {
               Object key = MapUtils.getObject(condition, "key");
               Expression keyExpression = parseCondition(key);
               Object map = MapUtils.getObject(condition, "map");
               Expression mapExpression = parseCondition(map);
               List<Expression> expressionList = Lists.newArrayList();
               expressionList.add(mapExpression);
               expressionList.add(keyExpression);
               return (Expression)new ExecuteExpression("Tools", "getMap", expressionList);
            }
            if (StringUtils.equals("checkList", type)) {
               List list = (List)MapUtils.getObject(condition, "params");
               List<Expression> expressionList = Lists.newArrayList();
               for (Object obj : list)
                  expressionList.add(parseCondition(obj));
               return (Expression)new ExecuteExpression("Tools", "checkList", expressionList);
            }
            if (StringUtils.equals("templet", type)) {
               String chName = MapUtils.getString(condition, "chName");
               Templet templet = (Templet)TempletRegister.templetMes.get(chName);
               List list = (List)MapUtils.getObject(condition, "params");
               List expressionList = Lists.newArrayList();
               expressionList.add("\"" + templet.getClassPath() + "\"");
               expressionList.add("\"" + templet.getMethodName() + "\"");
               for (Object obj : list)
                  expressionList.add(parseCondition(obj));
               return (Expression)new ExecuteExpression("TempletUtil", "executeTemplet", expressionList);
            }
            if (StringUtils.equals("clearList", type) || StringUtils.equals("clearMap", type)) {
               Object value = MapUtils.getObject(condition, "value");
               Expression valueExpression = parseCondition(value);
               return (Expression)new ExecuteExpression("Tools", type, new Expression[] { valueExpression });
            }
            if (StringUtils.equals("newMap", type) || StringUtils.equals("newList", type)) {
               Object value = MapUtils.getObject(condition, "value");
               Expression valueExpression = parseCondition(value);
               return (Expression)new NewExpression(valueExpression.toString(), type);
            }
            if (StringUtils.equals("ListAdd", type)) {
               Object list = MapUtils.getObject(condition, "list");
               Expression listExpression = parseCondition(list);
               Object value = MapUtils.getObject(condition, "value");
               Expression valueExpression = parseCondition(value);
               List<Expression> expressionList = Lists.newArrayList();
               expressionList.add(listExpression);
               expressionList.add(valueExpression);
               return (Expression)new ExecuteExpression("Tools", "listAdd", expressionList);
            }
            if (StringUtils.equals("Rule", type)) {
               List<Expression> expressions = Lists.newArrayList();
               expressions.add(parseCondition(MapUtils.getObject(condition, "groupId")));
               expressions.add(parseCondition(MapUtils.getObject(condition, "artifactId")));
               List list = (List)MapUtils.getObject(condition, "params");
               for (Object obj : list)
                  expressions.add(parseCondition(obj));
               return (Expression)new ExecuteExpression("Tools", "executeRule", expressions);
            }
            if (StringUtils.equals("property", type)) {
               Property property = new Property(MapUtils.getString(condition, "value"));
               return (Expression)property;
            }
            if (StringUtils.equals("variable", type)) {
               String variableName = MapUtils.getString(condition, "variableName");
               return (Expression)new ExecuteExpression("$variable", "getVariable", new Expression[] { (Expression)new StringValue(variableName) });
            }
            if (StringUtils.equals("setVariable", type)) {
               String varKey = MapUtils.getString(condition, "key");
               Object varValue = MapUtils.getObject(condition, "value");
               Expression valueExpression = parseCondition(varValue);
               return (Expression)new ExecuteExpression("$context", "setVariable", new Expression[] { (Expression)new StringValue(varKey), valueExpression });
            }
            if (StringUtils.equals("if", type)) {
               IfExpression ifExpression = new IfExpression();
               Map<String, Object> conditionConfig = MapUtils.getMap(condition, "condition");
               ifExpression.setConditionExpression(parseCondition(conditionConfig));
               List<Map<String, Object>> actions = (List<Map<String, Object>>)MapUtils.getObject(condition, "then");
               //TODO Streams.of(actions).forEach((Closure)new Object(ifExpression));

               List<Map<String, Object>> ifElsesConfig = (List<Map<String, Object>>)MapUtils.getObject(condition, "elseIfs");
               if (ifElsesConfig != null && !ifElsesConfig.isEmpty()) {
                  //Streams.of(ifElsesConfig).forEach((Closure) new Object(ifExpression));
               }
               Map<String, Object> elseConfig =  MapUtils.getMap(condition, "else");
               Map<String, Object> elseConditionConfig = MapUtils.getMap(elseConfig, "condition");
               if (elseConditionConfig != null) {
                  ElseExpression elseExpression = new ElseExpression();
                  elseExpression.setCondition(parseCondition(elseConditionConfig));
                  List<Map<String, Object>> elseActions = (List<Map<String, Object>>)MapUtils.getObject(elseConfig, "then");
                  //TODO Streams.of(elseActions).forEach((Closure)new Object(elseExpression));
                  ifExpression.setElseExpression(elseExpression);
               }
               return (Expression)ifExpression;
            }
         }
      }
      LOGGER.error("{}", JSONObject.toJSONString(condition));
      return null;
   }

   private static String generatorMVELExpression(Object obj) {
      if (obj instanceof String)
         return (new StringValue((String)obj)).toString();
      if (obj instanceof Number || obj instanceof Boolean)
         return (new StringValue("'" + obj + "'")).toString();
      if (obj instanceof Map)
         return generatorMVELExpression((Map<String, Object>)obj);
      if (obj instanceof List)
         return generatorMVELExpression((List<Object>)obj);
      return null;
   }

   private static String generatorMVELExpression(Map<String, Object> objectMap) {
      Set<String> keys = objectMap.keySet();
      StringBuilder builder = new StringBuilder("{");
      for (String key : keys) {
         builder.append("\\\"")
                 .append(key)
                 .append("\\\"")
                 .append(":");
         Object obj = objectMap.get(key);
         if (obj instanceof String)
            builder.append(((String)obj).replaceAll("\\\"", "\\\\\""));
         if (obj instanceof Map)
            builder.append(generatorMVELExpression((Map<String, Object>)obj));
         if (obj instanceof List)
            builder.append(generatorMVELExpression((List<Object>)obj));
         builder.append(",");
      }
      builder.delete(builder.length() - 1, builder.length());
      builder.append("}");
      return builder.toString();
   }

   private static String generatorMVELExpression(List<Object> objects) {
      StringBuilder builder = new StringBuilder("[");
      for (Object obj : objects) {
         if (obj instanceof String)
            builder.append(obj);
         if (obj instanceof Map)
            builder.append(generatorMVELExpression((Map<String, Object>)obj));
         if (obj instanceof List)
            builder.append(generatorMVELExpression((List<Object>)obj));
         builder.append(",");
      }
      builder.delete(builder.length() - 1, builder.length());
      builder.append("]");
      return builder.toString();
   }

   protected static Expression parseCondition(Object condition) {
      if (condition == null)
         return (Expression)new NullValue();
      if (condition instanceof Number)
         return parseCondition((Number)condition);
      if (condition instanceof String)
         return parseCondition((String)condition);
      if (condition instanceof Boolean)
         return parseCondition((Boolean)condition);
      if (condition instanceof Map)
         return parseCondition((Map<String, Object>)condition);
      return null;
   }

   protected static Expression parseCondition(String condition) {
      return (Expression)new StringValue(condition);
   }

   protected static Expression parseCondition(Boolean condition) {
      return (Expression)new BooleanValue(condition.toString());
   }

   protected static Expression parseCondition(Number condition) {
      if (condition instanceof Double)
         return (Expression)new DoubleValue(condition.toString());
      if (condition instanceof Integer)
         return (Expression)new IntValue(condition.toString());
      if (condition instanceof Float)
         return (Expression)new FloatValue(condition.toString());
      if (condition instanceof Long)
         return (Expression)new LongValue(condition.toString());
      return (Expression)new Value(condition.toString());
   }

   public static void main(String[] args) {}
}
